<?php


namespace EchoPHP\Database\TuxedoDriver;

use InvalidArgumentException;

class TuxedoTransactionStatement extends TransactionHandler {

    /**
     * 事务无影响行时是否回滚
     * @var bool|int
     */
    protected $rollBackIfNoAffects = true;
    /**
     * tuxedo服务名
     * @var
     */
    protected $server;
    /**
     * 事务操作dbid
     * @var
     */
    protected $dbId = 1;
    protected $tuxedoStatements = [];

    public function __construct($server, $dbId, bool $rollbackIfNoAffects, TuxedoStatement ...$tuxedoStatements) {
        parent::__construct();

        $this->server = strtoupper($server);
        $this->dbId = $dbId;
        $this->setRollbackIfNoAffects($rollbackIfNoAffects);

        $this->prepareStatements($tuxedoStatements);
    }

    /**
     * 获取服务名
     * @return string
     */
    public function getServer() {
        return $this->server;
    }

    /**
     * 获取数据库dbid
     * @return int
     */
    public function getDbId() {
        return $this->dbId;
    }

    /**
     * 获取回滚标记
     * @return bool|int
     */
    public function getRollbackIfNoAffects() {
        return $this->rollBackIfNoAffects;
    }

    /**
     * 获取执行语句
     * @return array
     */
    public function getStatements() {
        return $this->tuxedoStatements;
    }

    /**
     * 执行事务
     * @return mixed
     */
    public function execute() {
        if (count($this->tuxedoStatements) <= 1) {
            throw new InvalidArgumentException('事务操作至少需要2条语句');
        }
        $serverName = $this->server . '_BAT';
        $this->setServerName($serverName);
        $sendBufferParams = [
            $this->rollBackIfNoAffects, $this->dbId, count($this->tuxedoStatements)
        ];
        $this->setSendBuffer('');
        $this->pushSendBuffer($sendBufferParams);

        $querySqls = [];
        /* @var $statement TuxedoStatement */
        foreach ($this->tuxedoStatements as $statement) {
            $this->pushSendBuffer($statement->mergeSendBuffer(true));
            $querySqls[] = [
                'serverdbtype' => $statement->getDbType(),
                'dbid' => $statement->getDbId(),
                'query' => $statement->getSql(),
                'bindings' => $statement->getVar(),
            ];
        }
        return $this->run($querySqls);
    }

    /**
     * 设置事务是否回滚
     * @param $rollbackIfNoAffects
     * @return $this
     */
    public function setRollbackIfNoAffects(bool $rollbackIfNoAffects = true) {
        $this->rollBackIfNoAffects = $rollbackIfNoAffects ? 1 : 0;
        return $this;
    }

    /**
     * sql语句预处理
     * @param array $tuxedoStatements
     */
    protected function prepareStatements($tuxedoStatements) {
        $this->tuxedoStatements = [];
        foreach ($tuxedoStatements as $tuxedoStatement) {
            /* @var $tuxedoStatement TuxedoStatement */
            if ($this->server != $tuxedoStatement->getServer() || $this->dbId != $tuxedoStatement->getDbId()) {
                throw new InvalidArgumentException('该方法仅支持单库事务');
            }
            $this->tuxedoStatements[] = $tuxedoStatement;
        }
    }

    /**
     * 在事务队列前面加入一条执行语句
     * @param TuxedoStatement $tuxedoStatement
     * @return $this
     */
    public function prependStatement(TuxedoStatement $tuxedoStatement) {
        if ($this->server != $tuxedoStatement->getServer() || $this->dbId != $tuxedoStatement->getDbId()) {
            throw new InvalidArgumentException('该方法仅支持单库事务');
        }
        array_unshift($this->tuxedoStatements, $tuxedoStatement);
        return $this;
    }

    /**
     * 在执行队列尾部加入一条执行语句
     * @param TuxedoStatement $tuxedoStatement
     * @return $this
     */
    public function pushStatement(TuxedoStatement $tuxedoStatement) {
        if ($this->server != $tuxedoStatement->getServer() || $this->dbId != $tuxedoStatement->getDbId()) {
            throw new InvalidArgumentException('该方法仅支持单库事务');
        }
        array_push($this->tuxedoStatements, $tuxedoStatement);
        return $this;
    }

}